package ua.kratik.seabattle.game;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ua.kratik.seabattle.game.enums.CellState;
import ua.kratik.seabattle.game.enums.Direction;
import ua.kratik.seabattle.game.enums.ShootResult;

public class EnemysMap extends SeaMap {

	private static Logger logger = LoggerFactory.getLogger(EnemysMap.class);

	private Set<Coordinates> hitCells;

	private Set<Coordinates> destroyedCells;
	
	private Set<Coordinates> unknownCells;

	private Set<Coordinates> missedCells;
	
	private int destroyedShips;

	public EnemysMap(int seaSizeX, int seaSizeY) {
		super(seaSizeX, seaSizeY);
		cleanMap();
		destroyedShips = 0;
		hitCells = new HashSet<Coordinates>();
		destroyedCells = new HashSet<Coordinates>();
		unknownCells = new HashSet<Coordinates>();
		missedCells = new HashSet<Coordinates>();
		for(int x = 1; x <= seaSizeX; x++){
			for(int y = 1; y <= seaSizeY; y++){
				unknownCells.add(super.getCell(x, y));
			}
		}
	}

	@Override
	public void cleanMap() {
		logger.debug("Cleaning map to state UNKNOWN");
		super.fillWholeMap(CellState.UNKNOWN);
	}

	/**
	 * @return true if enemy ship was hit or destroyed
	 */
	public boolean drawSootResult(Coordinates cell, ShootResult shootResult) {
		boolean enemyWasHit = false;
		switch (shootResult) {
		case MISSED:
			logger.info("Enemy was missed. Processing...");
			enemyWasHit = false;
			fillCells(CellState.SHOT_AND_MISSED, cell);
			missedCells.add(cell);
			unknownCells.remove(cell);
			logger.info("Enemy was missed. Processing done.");
			break;
		case HIT:
			logger.info("Enemy was hit. Processing...");
			enemyWasHit = true;
			fillCells(CellState.SHOT_AND_HIT, cell);
			// Surround perimeter in future with value SUPPOSED_TO_BE_EMPTY
			hitCells.add(cell);
			unknownCells.remove(cell);
			logger.info("Enemy was hit. Processing done.");
			break;
		case DESTROYED:
			enemyWasHit = true;
			logger.info("Enemy was destroyed. Processing...");
			Set<Coordinates> adjactedHitCells = new HashSet<Coordinates>();
			findAdjactedCells(cell, Direction.NORTH, CellState.SHOT_AND_HIT, adjactedHitCells);
			findAdjactedCells(cell, Direction.SOUTH, CellState.SHOT_AND_HIT, adjactedHitCells);
			findAdjactedCells(cell, Direction.WEST, CellState.SHOT_AND_HIT, adjactedHitCells);
			findAdjactedCells(cell, Direction.EAST, CellState.SHOT_AND_HIT, adjactedHitCells);
			logger.trace("Adjected hit cells: " + adjactedHitCells.toString());
			
			fillCells(CellState.SHOT_AND_DESTROYED, cell);
			fillCells(CellState.SHOT_AND_DESTROYED, adjactedHitCells);
			destroyedCells.add(cell);
			destroyedCells.addAll(adjactedHitCells);
			hitCells.removeAll(adjactedHitCells);
			unknownCells.remove(cell);
			// Surround perimeter in future with value SUPPOSED_TO_BE_EMPTY
			// and all other parts of ship with walue SHOT_AND_DESTROYED
			logger.info("Enemy was destroyed. Processing done");
			break;
		}
		return enemyWasHit;
	}

	/**
	 * Search Cells in specified direction with specifeid cell state and add search results 
	 * to <code>collToAddResult</code>
	 * @param directionToSearch - direction to search
	 * @param stateToFind - state of cell which need to be found
	 * @param collToAddResult - search result will be added to this collection
	 */
	private void findAdjactedCells(Coordinates currentCell, 
									Direction directionToSearch, 
									CellState stateToFind,
									Collection<Coordinates> collToAddResult) {
		Coordinates cell = null;
		switch(directionToSearch){
		case NORTH:
			cell = super.getCell(currentCell.getX(), currentCell.getY()-1);
			break;
		case SOUTH:
			cell = super.getCell(currentCell.getX(), currentCell.getY()+1);
			break;
		case WEST:
			cell = super.getCell(currentCell.getX()-1, currentCell.getY());
			break;
		case EAST:
			cell = super.getCell(currentCell.getX()+1, currentCell.getY());
			break;
		}

		if(cell != null){
			//if true then continue searching in the same direction
			if(super.getCellState(cell) == stateToFind){
				collToAddResult.add(cell);
				findAdjactedCells(cell, directionToSearch, stateToFind, collToAddResult);
			}
		}
	}
	
}
